"""
01_hello_langgraph.py - Your First LangGraph Application
=========================================================
Chapter 4: Building a customer support classifier graph.

Concepts:
  - StateGraph: The graph builder
  - TypedDict: State definition
  - Nodes: Python functions that process state
  - Edges: Connections between nodes
  - START/END: Entry and exit points
  - compile(): Turns graph definition into runnable app
  - invoke(): Executes the graph with initial state

Run: python src/01_hello_langgraph.py
"""

from typing import TypedDict
from langgraph.graph import StateGraph, START, END


# ============================================================
# STEP 1: Define State
# ============================================================
# State is the shared data that flows through the graph.
# Every node reads from it and writes updates to it.

class SupportState(TypedDict):
    """State for our customer support graph.
    
    Think of this as a form that gets filled in
    as it passes through each department.
    """
    customer_message: str      # Input from customer
    category: str              # Classified category
    response: str              # Generated response  
    quality_score: float       # Quality check score
    is_approved: bool          # Whether response passed QA


# ============================================================
# STEP 2: Define Node Functions
# ============================================================
# Each node takes the FULL state and returns a dict
# of ONLY the fields it wants to update.

def classify_request(state: SupportState) -> dict:
    """Node 1: Classify the customer request.
    
    In production, this would use an LLM for classification.
    Here we use simple keyword matching for clarity.
    """
    message = state["customer_message"].lower()
    
    if any(word in message for word in ["bill", "charge", "payment", "invoice"]):
        category = "billing"
    elif any(word in message for word in ["bug", "error", "broken", "crash"]):
        category = "technical"
    elif any(word in message for word in ["cancel", "refund", "return"]):
        category = "cancellation"
    else:
        category = "general"
    
    print(f"  [Classifier] Detected category: {category}")
    return {"category": category}  # Only update 'category'


def generate_response(state: SupportState) -> dict:
    """Node 2: Generate a response based on category.
    
    Each category gets a tailored response template.
    """
    responses = {
        "billing": "I understand you have a billing concern. Let me look into your account and resolve this for you.",
        "technical": "I'm sorry you're experiencing a technical issue. Let me help troubleshoot this right away.",
        "cancellation": "I understand you'd like to cancel. Before we proceed, may I ask if there's anything we can do to help?",
        "general": "Thank you for reaching out! How can I assist you today?",
    }
    
    response = responses.get(state["category"], responses["general"])
    print(f"  [Generator] Response prepared ({len(response)} chars)")
    return {"response": response}  # Only update 'response'


def check_quality(state: SupportState) -> dict:
    """Node 3: Quality check the generated response.
    
    Evaluates response length and relevance.
    Returns both score and approval status.
    """
    response = state["response"]
    
    # Simple quality heuristics
    score = 0.0
    if len(response) > 20:
        score += 0.4
    if len(response) > 50:
        score += 0.3
    if state["category"] != "general":
        score += 0.2  # Specific responses score higher
    score = min(score + 0.1, 1.0)  # Base score
    
    approved = score >= 0.7
    
    print(f"  [QA Check] Score: {score:.2f}, Approved: {approved}")
    return {
        "quality_score": score,
        "is_approved": approved
    }


# ============================================================
# STEP 3: Build the Graph
# ============================================================

# Create a StateGraph with our state schema
graph = StateGraph(SupportState)

# Add nodes (name -> function)
graph.add_node("classify", classify_request)
graph.add_node("respond", generate_response)
graph.add_node("quality_check", check_quality)

# Add edges (define the execution flow)
graph.add_edge(START, "classify")           # Entry point
graph.add_edge("classify", "respond")        # Classify -> Respond
graph.add_edge("respond", "quality_check")   # Respond -> QA
graph.add_edge("quality_check", END)         # QA -> Exit


# ============================================================
# STEP 4: Compile and Run
# ============================================================

# compile() turns the graph definition into a runnable application
app = graph.compile()


# ============================================================
# DEMONSTRATION
# ============================================================

if __name__ == "__main__":
    print("=" * 60)
    print("01: Hello LangGraph - Customer Support Classifier")
    print("=" * 60)
    
    # Test cases
    test_messages = [
        "I found a bug in my dashboard that crashes every time I open it",
        "I need to cancel my subscription and get a refund",
        "Can you explain how the billing cycle works?",
        "Hello, I just want to say your product is great!",
    ]
    
    for msg in test_messages:
        print(f"\n{'─' * 50}")
        print(f"Customer: {msg}")
        print(f"{'─' * 50}")
        
        result = app.invoke({
            "customer_message": msg,
        })
        
        print(f"\n  Result:")
        print(f"    Category:  {result['category']}")
        print(f"    Response:  {result['response'][:80]}...")
        print(f"    Score:     {result['quality_score']:.2f}")
        print(f"    Approved:  {'✅' if result['is_approved'] else '❌'}")
    
    print(f"\n{'=' * 60}")
    print("✅ First LangGraph application complete!")
    print("=" * 60)
